<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Extend</title>
  </head>
  <body>
    <script>
      // bind函数，绑定this指向，返回的是一个包裹函数
      function bind(fn, thisArg) {
        return function wrap() {
          let args = new Array(arguments.length);
          for (let i = 0; i < args.length; i++) {
            args[i] = arguments[i];
          }
          return fn.apply(thisArg, args);
        };
      }

      // extend函数，把b对象上的继承到a对象，如果是函数就调用bind
      function extend(a, b, thisArg) {
        forEach(b, function assignValue(val, key) {
          if (thisArg && typeof val === "function") {
            a[key] = bind(val, thisArg);
          } else {
            a[key] = val;
          }
        });
        return a;
      }

      // forEach
      // obj=> object|array
      // fn 回调
      function forEach(obj, fn) {
        // 判断开始条件
        if (obj === null || typeof obj === "undefined") {
          return;
        }

        // 判断是不是object，如果不是则添加到数组中
        if (typeof obj !== "object") {
          obj = [obj];
        }

        // 分别遍历2中循环，array和object
        if (isArray(obj)) {
          for (let i = 0; i < obj.length; i++) {
            fn.call(null, obj[i], i, obj);
          }
        } else {
          for (let key in obj) {
            if (Object.prototype.hasOwnProperty.call(obj, key)) {
              fn.call(null, obj[key], key, obj);
            }
          }
        }
      }

      function isArray(val) {
        return Array.isArray(val);
      }

      let obj1 = {
        a: 12,
        b: 22,
      };

      let obj2 = {
        a: 999,
        b: "tony",
        c: function () {
          console.log(123);
        },
      };

      extend(obj1, obj2);

      console.log(obj1);
    </script>
  </body>
</html>
